package com.quectel.taskserver.job.scheduling;

import cn.hutool.core.date.DateUtil;
import cn.hutool.core.lang.func.LambdaUtil;
import com.quectel.base.tuple.Tuple2;
import com.quectel.business.common.scheduling.SchedulingLeaveBusiness;
import com.quectel.constant.core.scheduling.SchedulingApplyConstants;
import com.quectel.constant.core.scheduling.SchedulingLeaveConstants;
import com.quectel.constant.global.SystemConstants;
import com.quectel.core.module.dept.dto.DeptPersonDto;
import com.quectel.core.module.dept.service.DeptPersonService;
import com.quectel.core.module.scheduling.dto.SchedulingLeaveBalanceDto;
import com.quectel.core.module.scheduling.dto.SchedulingLeaveConfigDto;
import com.quectel.core.module.scheduling.dto.SchedulingLeavePersonBindingDto;
import com.quectel.core.module.scheduling.service.SchedulingLeaveBalanceService;
import com.quectel.core.module.scheduling.service.SchedulingLeaveConfigService;
import com.quectel.core.module.scheduling.service.SchedulingLeavePersonBindingService;
import com.quectel.core.module.schedulingapply.dto.vo.SchedulingTimeVO;
import com.quectel.util.common.DateUtils;
import com.quectel.util.common.Response;
import org.apache.commons.collections4.CollectionUtils;
import org.apache.dubbo.config.annotation.DubboReference;
import org.apache.shardingsphere.elasticjob.api.ShardingContext;
import org.apache.shardingsphere.elasticjob.simple.job.SimpleJob;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;

import java.math.BigDecimal;
import java.util.Date;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

/**
 * @author zhangheng
 * @date 2023/08/01 7:24 下午
 */
@Component
public class SchedulingLeaveBalanceGrantTask implements SimpleJob {

    private static final Logger LOGGER = LoggerFactory.getLogger(SchedulingLeaveBalanceGrantTask.class);

    @DubboReference
    private DeptPersonService deptPersonService;
    @DubboReference
    private SchedulingLeaveConfigService schedulingLeaveConfigService;
    @DubboReference
    private SchedulingLeavePersonBindingService schedulingLeavePersonBindingService;
    @DubboReference
    private SchedulingLeaveBalanceService schedulingLeaveBalanceService;
    @Autowired
    private SchedulingLeaveBusiness schedulingLeaveBusiness;

    @Override
    public void execute(ShardingContext shardingContext) {
        gen();
    }

    /**
     * 每日考勤生成
     * 提前生成下一天的，原因是当天可能提前打卡明天的
     */
    private void gen() {
        LOGGER.debug("考勤假期余额自动发放");
        //查询所有的限额假期类型
        Map<String, Object> params = new HashMap<>();
        params.put(LambdaUtil.getFieldName(SchedulingLeaveConfigDto::getStatus), SystemConstants.YES);
        params.put(LambdaUtil.getFieldName(SchedulingLeaveConfigDto::getLimitFlag), SystemConstants.YES);
        List<SchedulingLeaveConfigDto> schedulingLeaveConfigDtos = schedulingLeaveConfigService.queryList(params);
        if (CollectionUtils.isEmpty(schedulingLeaveConfigDtos)) {
            return;
        }
        Date now = new Date();
        for (SchedulingLeaveConfigDto schedulingLeaveConfigDto : schedulingLeaveConfigDtos) {
            //校验配置
            Response response = schedulingLeaveBusiness.checkLeaveConfig(schedulingLeaveConfigDto);
            if (!response.isSuccess()) {
                LOGGER.debug("假期配置有误，假期Id:{}", schedulingLeaveConfigDto.getId());
                continue;
            }
            //查询绑定人员
            List<SchedulingLeavePersonBindingDto> schedulingLeavePersonBindingDtos = schedulingLeavePersonBindingService.selectByLeaveId(schedulingLeaveConfigDto.getId());
            if (CollectionUtils.isEmpty(schedulingLeavePersonBindingDtos)) {
                continue;
            }
            for (SchedulingLeavePersonBindingDto schedulingLeavePersonBindingDto : schedulingLeavePersonBindingDtos) {
                DeptPersonDto deptPersonDto = deptPersonService.selectCacheById(schedulingLeavePersonBindingDto.getDeptPersonId());
                if (deptPersonDto == null || deptPersonDto.getJoinedDate() == null || deptPersonDto.getFirstJobDate() == null) {
                    LOGGER.debug("员工不存在或者配置有误，员工id:{}", schedulingLeavePersonBindingDto.getDeptPersonId());
                    continue;
                }
                //如果是自动转余额则不用处理
                if((schedulingLeaveConfigDto.getGrantRule() != null) && schedulingLeaveConfigDto.getGrantRule().getMethod().equals(SchedulingLeaveConstants.GrantMethodEnum.AUTO_CONVERT.getMethod())){
                    continue;
                }

                //根据配置获取开始时间和结束时间
                Response<Date> startTime = schedulingLeaveBusiness.getStartTime(schedulingLeaveConfigDto.getGrantRule(), now, deptPersonDto.getJoinedDate());
                if (!startTime.isSuccess()) {
                    continue;
                }
                Response<Tuple2<Date, Date>> endTimeResponse = schedulingLeaveBusiness.getEndTime(schedulingLeaveConfigDto.getGrantRule(), now);
                if (!endTimeResponse.isSuccess()) {
                    continue;
                }
                //判断这个时间是否和其他时间交叉,如果交叉则不能生成
                boolean timeCrossed = schedulingLeaveBusiness.isTimeCrossed(schedulingLeaveConfigDto.getId(),
                        deptPersonDto.getId(),
                        DateUtil.year(startTime.getData()),
                        DateUtils.format(startTime.getData(), DateUtils.FormatType.COMMON),
                        DateUtils.format(endTimeResponse.getData().getT1(), DateUtils.FormatType.COMMON)
                );
                //如果不交叉则可以继续
                if (timeCrossed) {
                    LOGGER.debug("余额时间有交叉,人员id:{},开始时间:{},结束时间:{}", schedulingLeavePersonBindingDto.getDeptPersonId(), startTime.getData(), endTimeResponse.getData().getT1());
                    continue;
                }

                //可生发放余额
                Response<SchedulingTimeVO> grantBalanceByCombinedGrant = schedulingLeaveBusiness.getGrantBalanceByCombinedGrant(schedulingLeaveConfigDto.getMinUnit(), schedulingLeaveConfigDto.getGrantRule(), deptPersonDto.getJoinedDate(), deptPersonDto.getFirstJobDate());

                if (!grantBalanceByCombinedGrant.isSuccess()) {
                    LOGGER.debug("根据配置生成发放数量失败,配置id:{},人员id:{}", schedulingLeaveConfigDto.getId(), schedulingLeavePersonBindingDto.getDeptPersonId());
                    continue;
                }

                SchedulingLeaveBalanceDto dto = new SchedulingLeaveBalanceDto();
                dto.setLeaveId(schedulingLeaveConfigDto.getId());
                dto.setPersonId(deptPersonDto.getId());
                dto.setBalance(BigDecimal.ZERO);
                dto.setUsedBalance(BigDecimal.ZERO);
                dto.setUnit(schedulingLeaveConfigDto.getMinUnit());
                dto.setYear(DateUtil.year(startTime.getData()));
                dto.setStartTime(startTime.getData());
                dto.setEndTime(endTimeResponse.getData().getT1());
                dto.setEffectiveStartTime(startTime.getData());
                dto.setEffectiveEndTime(endTimeResponse.getData().getT2());
                dto.setCreateTime(new Date());

                //先保存 然后更新
                dto.setId(schedulingLeaveBalanceService.save(dto));

                //更新发放的余额
                schedulingLeaveBalanceService.updateBalance(
                        deptPersonDto.getId(),
                        SchedulingApplyConstants.BalanceTypeEnum.AUTO_GRANT.getType(),
                        schedulingLeaveConfigDto.getId(),
                        dto.getId(),
                        grantBalanceByCombinedGrant.getData().getTimeLength()
                        , grantBalanceByCombinedGrant.getData().getTimeUnit()
                );

            }

        }

    }

}
